﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading;
using Shared_Mutex_Manager_Test.Locking;

namespace Shared_Mutex_Manager_Test
{
    /// <summary>
    ///     Simple test of Shared Mutex Manager
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {

            //spin up 5 instances
            if (!args.Any())
            {
                for (int i = 0; i < 5; i++)
                {
                    Process.Start(Assembly.GetExecutingAssembly().GetName().CodeBase, "nospin");
                }
            }

            CreateSharedMutexAndWait_Test();
            Clear();
            SharedMutexInvoke_Action_Test();
            Console.ReadLine();
        }

        /// <summary>
        ///  Test the CreateSharedMutexAndWait method

        static void CreateSharedMutexAndWait_Test()
        {
            var pid = Process.GetCurrentProcess().Id;
            var test1 = new Action(() =>
            {
                var thread = Thread.CurrentThread.ManagedThreadId;
                var man = new SharedMutexManager();
                man.AbandonedMutexEncountered += (sender, args) => Console.Out.WriteLine(args.Exception);
                WriteLine("PID: " + pid + " - Thread: " + thread + " waiting for mutex");
                var m1 = man.CreateSharedMutexAndWait("test");
                WriteLine("PID: " + pid + " - Thread: " + thread + " owns the mutex");
                WriteLine("PID: " + pid + " - Thread: " + thread + " press any key to release...");
                Console.ReadLine();
                WriteLine("PID: " + pid + " - Thread: " + thread + " release requested from user");
                m1.ReleaseMutex();
                WriteLine("PID: " + pid + " - Thread: " + thread + " released the mutex");
                m1.Dispose();
            });

            WriteLine("Starting CreateSharedMutexAndWait Test");
            var r1 = test1.BeginInvoke(test1.EndInvoke, null);
            var r2 = test1.BeginInvoke(test1.EndInvoke, null);
            r1.AsyncWaitHandle.WaitOne();
            r2.AsyncWaitHandle.WaitOne();
            WriteLine(pid + " - CreateSharedMutexAndWait Test Completed! Press any key to continue...");
        }

        /// <summary>
        ///     Test the SharedMutexInvoke Method
        /// </summary>
        static void SharedMutexInvoke_Action_Test()
        {
            var pid = Process.GetCurrentProcess().Id;
            var test2 = new Action(() =>
            {
                var thread = Thread.CurrentThread.ManagedThreadId;
                Console.Out.WriteLine("PID: " + pid + " - Thread: " + thread + " waiting for mutex");
                var man = new SharedMutexManager();
                man.AbandonedMutexEncountered += (sender, args) => Console.Out.WriteLine(args.Exception);

                man.SharedMutexInvoke(() =>
                {
                    WriteLine("PID: " + pid + " - Thread: " + thread + " owns the mutex");
                    WriteLine("PID: " + pid + " - Thread: " + thread + " processing critical section");
                    WriteLine("PID: " + pid + " - Thread: " + thread + " press any key to release...");
                    Console.ReadLine();
                    WriteLine("PID: " + pid + " - Thread: " + thread + " release requested from user");
                }, "test");

                WriteLine("PID: " + pid + " - Thread: " + thread + " released the mutex");
            });

            WriteLine("Starting SharedMutexInvoke Test");
            var r1 = test2.BeginInvoke(test2.EndInvoke, null);
            var r2 = test2.BeginInvoke(test2.EndInvoke, null);
            r1.AsyncWaitHandle.WaitOne();
            r2.AsyncWaitHandle.WaitOne();
            WriteLine(pid + " - SharedMutexInvoke(Action) Test Completed! Press any key to continue...");
        }

        private static void WriteLine(string text)
        {
            Console.Out.WriteLine(text);
        }
        private static void Clear()
        {
            Console.Clear();
        }
    }
}
